var webconfig = require("../../../webconfig").webconfig;
import { WebException } from '../../controller/webException';
import http = require("http");
import https = require("https");

let httpClient: any = http;
if (webconfig.isHttps) {
    httpClient = https;
}

/**
 * 
 * 
 * @export
 * @class MPJRequest
 */
class MPJRequest implements IMPJRequest {
    /**
     * 
     * 
     * @param {any} url
     * @returns
     * 
     * @memberOf MPJRequest
     */
    Get<T>(url) {
        return this.Request<T>(url, "GET");
    }
    /**
     * 
     * 
     * @param {string} url
     * @param {any} data
     * @returns
     * 
     * @memberOf MPJRequest
     */
    Put(url: string, data) {
        return this.Request(url, "PUT", data);
    }

    /**
     * 获取带参数的url地址
     * 
     * @param {string} relativePath 接口url地址
     * @param {any} params 地址参数
     * @returns {string}
     * 
     * @memberOf MPJRequest
     */
    GetUrl(relativePath: string, params?): string {
        if (Array.isArray(relativePath)) {
            relativePath = relativePath.join('/');
        }
        if (relativePath[0] == '/') {
            relativePath = relativePath.substring(1);
        }
        var url = [webconfig.mpjServerRootURL, relativePath].join('/');
        if (params) {
            url += '?' + this.ToQueryString(params);
        }
        return url;
    }

    /**
     * 
     * 
     * @param {string} url
     * @param {any} data
     * @returns
     * 
     * @memberOf MPJRequest
     */
    Post<T>(url: string, data) {
        return this.Request<T>(url, "POST", data);
    }

    private Request<T>(url: string, method: string, data?): Promise<T> {
        return new Promise((resovle, reject) => {
            let content = JSON.stringify(data);
            let options = {
                hostname: webconfig.cloudHost,
                port: webconfig.cloudPort,
                path: url,
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    "Content-length": Buffer.byteLength(content)
                }
            };

            let req = httpClient.request(options, function (res) {
                res.setEncoding('utf8');
                res.data = '';
                res.on('data', function (chunk: any) {
                    res.data += chunk;
                });

                res.on('end', function () {
                    try {
                        let d = JSON.parse(res.data);
                        resovle(d);
                    }
                    catch (err) {
                        reject(err);
                    }
                });
            });

            req.on('error', function (e) {
                console.log('problem with request: ' + e.message);
                reject(new WebException(this, e.message));
            });

            // write data to request body  
            req.write(content);
            req.end();
        });
    }

    private ToQueryString(obj) {
        var str = [];
        for (var p in obj)
            if (obj.hasOwnProperty(p)) {
                str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
            }
        return str.join("&");
    }
}

export class MPJRequestManager {
    static Current: MPJRequestManager = new MPJRequestManager();
    constructor(){
        if(!this.mpjRequest) this.mpjRequest = new MPJRequest();
    }
    private mpjRequest: IMPJRequest;
    GetMPJRequest(): IMPJRequest {
        return this.mpjRequest;
    }
    RegistMPJRequest(mpjRequest?: IMPJRequest) {
         this.mpjRequest = mpjRequest;
    }
}

export class MPJRequestMock implements IMPJRequest {
    constructor() { }
    private mockData: { key: string, data: any }[] = [];
    MockData(key: string, data: any) {
        this.mockData.push({
            key: key,
            data: data
        });
    }
    Get<T>(url: any): T {
        throw new Error("Method not implemented.");
    }
    Put(url: string, data: any) {
        throw new Error("Method not implemented.");
    }
    GetUrl(relativePath: string, params?: any): string {
        throw new Error("Method not implemented.");
    }
    Post<T>(url: string, data: any): T {
        let r = this.mockData.find(x => x.key == url);
        if (r) return r.data;
        else return null;
    }
}

interface IMPJRequest {
    Get<T>(url): T;
    Put(url: string, data);
    GetUrl(relativePath: string, params?): string;
    Post<T>(url: string, data): T;
}